<?php

namespace addons\csmitsm\library\xcore\xcore\utils;

use addons\csmitsm\library\xcore\xcore\XcException;
use addons\csmitsm\library\sdnode\xstack\utils\XsRandomUtils;

/**
 * Thinkphp 5 Docs
 * https://www.kancloud.cn/manual/thinkphp5/135185
 * 
 * @usage or
    ->where(function ($query) use ($sessionAdminid, $sessionAdminGroupids) {
        $query->where("xcflow_toaudit_admin_id", "=", $sessionAdminid)
            ->whereOr("xcflow_toaudit_role_id", "in", $sessionAdminGroupids);
    })
 * @usage or
    ->where("name|content", "like", "%test")
 * @usage where in select
    ->where('id', 'in', function ($query) use ($sessionAdminid) {
        $query->table(XcDatabaseUtils::appendTablePrefix('csmitsm_xcflow_instancetrace'))
            ->where('status', '=', 'normal')
            ->where('trace_admin_id', '=', $sessionAdminid)
            ->field('xcflow_instance_id');
    })
 */
class XcDaoUtils
{

    /**
     * 代替 saveMapping
     * Save Dmo#csmitsm_dmocategory_ids to Dmo2category's List
        $dmo = XcDaoUtils::getRowById(new \app\admin\model\csmitsm\Dmo(), 1);
        XcDaoUtils::syncMultiColumnToRelateTable(new \app\admin\model\csmitsm\Dmo2category(), "csmitsm_dmo_id", $dmo->id, "csmitsm_dmocategory_id", $dmo->csmitsm_dmocategory_ids, ['user_id' => 1]);
     * @return void
     */
    public static function syncMultiColumnToRelateTable($mapDao, $id_field, $id, $ref_id_field, $ref_ids, $dafaultDatas = [])
    {
        if (true) {
            $list = $mapDao->where($id_field, 'in', $id)->select();
            foreach ($list as $item) {
                $item->delete();
            }
        }

        if (true) {
            $ref_id_array = explode(",", $ref_ids);
            foreach ($ref_id_array as $ref_id) {
                $model = [
                    $id_field => $id,
                    $ref_id_field => $ref_id,
                ];
                $mapDao->create(array_merge($model, $dafaultDatas));
            }
        }
    }
    /**
     * 用户1:N时,保存冗余数据到mapping表(2)
     * create:
     * XcDaoUtils::saveMapping(new \app\admin\model\AuthGroup2Rule(),"airoom_aiitem_id",$result,$result,"airoom_aicategory_id",$params['rules']);
     * update:
     * XcDaoUtils::saveMapping(new \app\admin\model\AuthGroup2Rule(), "airoom_aiitem_id",$row->id, "airoom_aicategory_id", $params['rules']);
     */
    // public static function saveMapping($mapDao, $id_field, $id, $ref_id_field, $ref_ids)
    // {
    //     if (true) {
    //         $list = $mapDao->where($id_field, 'in', $id)->select();
    //         foreach ($list as $item) {
    //             $item->delete();
    //         }
    //     }

    //     if (true) {
    //         $ref_id_array = explode(",", $ref_ids);
    //         foreach ($ref_id_array as $ref_id) {
    //             $model = [
    //                 $id_field => $id,
    //                 $ref_id_field => $ref_id,
    //             ];
    //             $mapDao->create($model);
    //         }
    //     }
    // }

    /**
     * 根据ID获取记录（附带assert）
       XcDaoUtils::getRowById(new \app\admin\model\xpdemo\project(),10,true,true);
     * @return object
     */
    public static function getRowById($dao, $id, $hasNormalField = false, $isAssert = true, $fields = "*")
    {
        $dao->alias('t');
        $dao->where('t.id', '=', $id);
        if ($hasNormalField === true) {
            $dao->where('t.status', 'in', ['normal', 'draft']);
        }
        $dao->field($fields);
        $row = $dao->find();

        // XcDebugUtils::showSql($dao);
        if ($isAssert === true) {
            XcAssertUtils::assertNotNull($row, "getRowById null", "<b>XcDaoUtils getRowById AssertNull</b><BR>" . $dao->getLastSql());
        }

        return $row;
    }

    /**
     * 查询row记录-根据多个等号查询字段
       XcDaoUtils::getRowBySql(new \app\admin\model\xpdemo\project(),[['name','=','xx']],["id,name"],true,true);
     * @return object
     */
    public static function getRowBySql($dao, $whereFieldValues, $fieldString = null, $hasNormalField = true, $isAssert = false, $orders = "id desc")
    {
        $row = null;
        $dao->alias('t');
        if ($fieldString != null) {
            $dao->field($fieldString);
            //var_dump($fieldString);
        }
        foreach ($whereFieldValues as $item) {
            $dao->where($item[0], $item[1], $item[2]);
        }
        if ($hasNormalField != null) {
            $dao->where('t.status', 'in', ['normal', 'draft']);
        }
        $dao = $dao->order($orders);
        $row = $dao->find();
        // XcDebugUtils::showSql($dao);

        if ($isAssert === true) {
            XcAssertUtils::assertNotNull($row, "getRowById null", "<b>XcDaoUtils getRowBySql AssertNull</b><BR>" . $dao->getLastSql());
        }
        return $row;
    }

    public static function randomRowBySql($dao, $whereFieldValues, $fieldString = null, $hasNormalField = true, $isAssert = true)
    {
        $list = static::getListBySql($dao, $whereFieldValues, $fieldString, $hasNormalField);
        $row = static::randomRow($list);

        if ($isAssert === true) {
            XcDebugUtils::logger("<b>XcDaoUtils randomRowBySql Error</b><BR>" . $dao->getLastSql());
            XcAssertUtils::assertNotNull($row, "getRowById null");
        }
        return $row;
    }

    /**
     * 查询List记录-根据多个等号查询字段和排序
       XcDaoUtils::getListBySql(new \app\admin\model\xpdemo\project(),[['name','=','xx']],["id,name"],["id","desc"],true);
     * @return array
     */
    public static function getListBySql($dao, $whereFieldValues, $fieldString = null, $orders = null, $hasNormalField = true, $pageLimit = null)
    {
        $list = null;
        $dao = $dao->alias('t');
        if ($fieldString != null) {
            $dao = $dao->field($fieldString);
        }
        foreach ($whereFieldValues as $item) {
            if ($item == null) {
                continue;
            }
            if (count($item) == 2) {
                $dao->where($item[0], $item[1]);
            } else {
                $dao->where($item[0], $item[1], $item[2]);
            }
        }
        if ($hasNormalField === true) {
            $dao->where('t.status', 'in', ['normal', 'draft']);
        }
        if ($pageLimit) {
            $dao->limit($pageLimit[0], $pageLimit[1]);
        }
        if ($orders != null) {
            $dao->order($orders);
        }
        $list = $dao->select();
        // XcDebugUtils::showSql($dao);
        return $list;
    }

    /**
     * 分页查询
        [$list, $count] = getPageListBySql($dao, [], 0, 10);
     * @return array
     */
    public static function getPageListBySql($dao, $whereFieldValues, $offset, $limit, $fieldString = null, $orders = null, $hasNormalField = true)
    {
        $page = [$offset, $limit];
        $list = static::getListBySql(clone $dao, $whereFieldValues,$fieldString, $orders, $hasNormalField, $page);
        $count = static::getCountBySql($dao, $whereFieldValues, $fieldString, $orders, $hasNormalField);
        return [$list, $count];
    }

    public static function getCountBySql($dao, $whereFieldValues, $hasNormalField = true)
    {
        $dao->alias('t');
        foreach ($whereFieldValues as $item) {
            if ($item == null) {
                continue;
            }
            if (count($item) == 2) {
                $dao->where($item[0], $item[1]);
            } else {
                $dao->where($item[0], $item[1], $item[2]);
            }
        }
        if ($hasNormalField === true) {
            $dao->where('t.status', 'in', ['normal', 'draft']);
        }
        $count = $dao->count();
        return $count;
    }

    /**
     * 一条记录多选字段的绑定
        $dmo = XcDaoUtils::getRowById(new \app\admin\model\csmitsm\Dmo(), 1);
        XcDaoUtils::bindDbRowMultiColumn($dmo, "csmitsm_dmocategory_ids", new \app\admin\model\csmitsm\Dmocategory(), "csmitsm_dmocategory_ids", "name"); // csmitsm_dmocategory_ids --> csmitsm_dmocategory_ids_name=[]
     */
    public static function bindDbRowMultiColumn(&$row, $key, $dao, $daoalias, $daofieldname)
    {
        $ids = [];
        if (isset($row[$key])) {
            if ($row[$key] != null && $row[$key] != '') {
                $tt = explode(',', $row[$key]);
                $ids = array_merge($tt, $ids);
            }
        }

        $keylist = $dao->where("id", "in", $ids)
            ->field("id," . $daofieldname)
            ->select();

        $keynames = [];
        foreach ($keylist as $keyrow) {
            $keynames['D' . $keyrow['id']] = $keyrow[$daofieldname];
        }

        $tt = [];

        $mutilkeystring = isset($row[$key]) ? $row[$key] : null;
        if ($mutilkeystring != null && $mutilkeystring != '') {
            $mutilkeys = explode(',', $mutilkeystring);
            foreach ($mutilkeys as $item_key) {

                if (isset($keynames['D' . $item_key])) {
                    $tt[] = $keynames['D' . $item_key];
                }
            }
        }
        $row[$daoalias . "_" . $daofieldname] = $tt;
    }

    /**
     * 1:1 单字段的绑定
        $dmo = XcDaoUtils::getRowById(new \app\admin\model\csmitsm\Dmo(), 1);
        XcDaoUtils::bindDbRowColumn($dmo, "csmitsm_dmocategory_id", new \app\admin\model\csmitsm\Dmocategory(), "csmitsm_dmocategory", ["name"]); // csmitsm_dmocategory_id->csmitsm_dmocategory_name
     * @return void
     */
    public static function bindDbRowColumn(&$row, $key, $dao, $daoalias, $daofieldnames)
    {
        $row2 = XcDaoUtils::getRowById($dao, $row[$key], true, false, $daofieldnames);
        if ($row2 != null) {
            foreach (static::_getData($row2) as $k => $v) {
                $newkeyname = ($daoalias == null) ? $k : ("{$daoalias}_{$k}");
                $row[$newkeyname] = $v;
            }
        }
    }

    /**
     * 1:N 多选字段的绑定
        $list = XcDaoUtils::getListBySql(new \app\admin\model\csmitsm\Dmo(),[]);
        XcDaoUtils::bindDbListMultiColumn($list, "csmitsm_dmocategory_ids", new \app\admin\model\csmitsm\Dmocategory(), "csmitsm_dmocategory_id", "name"); // csmitsm_dmocategory_ids(string)->csmitsm_dmocategory_name(array)
     */
    public static function bindDbListMultiColumn(&$list, $key, $dao, $daoalias, $daofieldname)
    {
        $ids = [];
        foreach ($list as $item) {
            if (isset($item[$key])) {
                if ($item[$key] != null && $item[$key] != '') {
                    $tt = explode(',', $item[$key]);
                    $ids = array_merge($tt, $ids);
                }
            }
        }

        $keylist = $dao->where("id", "in", $ids)
            ->field("id," . $daofieldname)
            ->select();

        $keynames = [];
        foreach ($keylist as $keyrow) {
            $keynames['D' . $keyrow['id']] = $keyrow[$daofieldname];
        }

        foreach ($list as $i => $item) {
            $tt = [];

            $mutilkeystring = isset($item[$key]) ? $item[$key] : null;
            if ($mutilkeystring != null && $mutilkeystring != '') {
                $mutilkeys = explode(',', $mutilkeystring);
                foreach ($mutilkeys as $item_key) {

                    if (isset($keynames['D' . $item_key])) {
                        $tt[] = $keynames['D' . $item_key];
                    }
                }
            }
            $list[$i][$daoalias . "_" . $daofieldname] = $tt;
        }
    }

    /**
     * 将list的id对应的记录绑定在list上,比如tastgroup2user的list需要将fa_user记录绑定上list
        $list = XcDaoUtils::getListBySql(new \app\admin\model\csmitsm\Dmo(),[]);
        XcDaoUtils::bindDbListColumn($list, "csmitsm_dmocategory_id", new \app\admin\model\csmitsm\Dmocategory(), "csmitsm_dmocategory_id", ["name"]);  // csmitsm_dmocategory_id->csmitsm_dmocategory_name
     */
    public static function bindDbListColumn(&$list, $key, $dao, $daoalias, $daofieldnames)
    {
        $ids = [];

        foreach ($list as &$item2) {
            $item_key = isset($item2[$key]) ? $item2[$key] : null;
            foreach ($daofieldnames as $daofieldname) {
                $newkeyname = "{$daoalias}_{$daofieldname}";
                $item2[$newkeyname] = null;
            }
        }

        foreach ($list as $item) {
            if (isset($item[$key])) {
                $ids[] = $item[$key];
            }
        }

        $keylist = $dao->where("id", "in", $ids)
            ->field("id," . join(",", $daofieldnames))
            ->select();

        $keynames = [];
        foreach ($keylist as $keyrow) {
            $daofieldvalues = [];
            foreach ($daofieldnames as $daofieldname) {
                $daofieldvalues[$daofieldname]  = $keyrow[$daofieldname];
            }
            $keynames['D' . $keyrow['id']] = $daofieldvalues;
        }

        foreach ($list as $i => $item) {
            $item_key = isset($item[$key]) ? $item[$key] : null;
            if (isset($keynames['D' . $item_key])) {
                foreach ($keynames['D' . $item_key] as $daofieldname => $daofieldvalue) {
                    $newkeyname = ($daoalias == null) ? $daofieldname : ("{$daoalias}_{$daofieldname}");

                    $list[$i][$daoalias != null ? $newkeyname : $key] = $daofieldvalue;
                }
            } else {
                $list[$i][$key] = null;
            }
        }
    }


    /**
     * 用于1:1的数据拼接
        $list1 = XcDaoUtils::getListBySql(new \app\admin\model\csmitsm\Dmo(),[]);
        $list2 = XcDaoUtils::getListBySql(new \app\admin\model\csmitsm\Dmoapply(),[]);
        XcDaoUtils::bindListColumn2list($list1, "csmitsm_dmoapply_id", $list2, "id", "csmitsm_dmoapply"); // column_list2 -> csmitsm_dmoapply_xxx
     * @return void
     */
    public static function bindListColumn2list(&$list, $key, $list2, $key2, $daoalias)
    {
        foreach ($list as &$item) {
            foreach ($list2 as $item2) {
                if ($item[$key] == $item2[$key2]) {
                    foreach (static::_getData($item2) as $kk => $vv) {
                        $keyname = "{$daoalias}_{$kk}";
                        $item[$keyname] = $vv;
                    }
                }
            }
        }
    }

    /**
     * 在bindListColumn2list基础上,支持多字段1:1匹配
     *
        $list1 = XcDaoUtils::getListBySql(new \app\admin\model\csmitsm\Dmo(),[]);
        $list2 = XcDaoUtils::getListBySql(new \app\admin\model\csmitsm\Dmoapply(),[]);
        XcDaoUtils::bindListColumn2listByKeys($list1, ["csmitsm_dmoapply_id"], $list2, ["id"], "csmitsm_dmoapply");
     * @return void
     */
    public static function bindListColumn2listByKeys(&$list, $keys, $list2, $keys2, $daoalias)
    {
        if (count($keys) != count($keys2)) {
            throw new XcException("系统错误", 0, null, "bindListColumn2listByKeys中key参数错误");
        }
        foreach ($list as &$item) {
            foreach ($list2 as $item2) {
                $ifEqual = true;
                foreach ($keys as $index => $key) {
                    if ($item[$keys[$index]] != $item2[$keys2[$index]]) {
                        $ifEqual = false;
                    }
                }

                if ($ifEqual === true) {
                    foreach (static::_getData($item2) as $kk => $vv) {
                        $keyname = "{$daoalias}_{$kk}";
                        $item[$keyname] = $vv;
                    }
                }
            }
        }
    }

    private static function _getData($item)
    {
        if (is_array($item)) {
            return $item;
        } else {
            return $item->getData();
        }
    }

    /**
     * 
     *
        $list1 = XcDaoUtils::getListBySql(new \app\admin\model\csmitsm\Dmo(),[["id", "in", [1, 2]]]);
        $list2 = XcDaoUtils::getListBySql(new \app\admin\model\csmitsm\Dmo(),[["id", "in", [2, 3]]]);
        $list3 = XcDaoUtils::mergeList($list1, $list2, "id");
        XcDebugUtils::showDbList($list3);
     * @return array
     */
    public static function mergeList($fromList, $toList, $mergeFieldName)
    {
        $list = [];
        $mergeFieldValues = [];
        foreach ($fromList as $item) {
            $mergeFieldValues[] = $item[$mergeFieldName];
            $list[] = $item;
        }
        foreach ($toList as $item) {
            if (!in_array($item[$mergeFieldName], $mergeFieldValues)) {
                $list[] = $item;
            }
        }
        return $list;
    }

    /**
     * 
        $list = XcDaoUtils::getListBySql(new \app\admin\model\csmitsm\Dmo(),[]);
        $list2 = XcDaoUtils::getValuesFromList($list, 'id'); -> [1, 2, 3]
     * @return array
     */
    public static function getValuesFromList($list, $keyname)
    {
        $values = [];
        foreach ($list as $item) {
            $values[] = $item[$keyname];
        }
        return $values;
    }


    public static function cloneRow2Model($row)
    {
        $model = [];
        foreach (static::_getData($row) as $key => $value) {
            $model[$key] = $value;
        }
        return $model;
    }


    private static function randomRow($rows)
    {
        if (count($rows) == 0) {
            return null;
        }
        if (count($rows) == 1) {
            return array_shift($rows);
            //return $rows[0];
        }
        $list = XsRandomUtils::randomRows($rows, 1);
        return $list[0];
    }
    // private static function randomRows($rows, $rowCount)
    // {
    //     if (count($rows) <= $rowCount) {
    //         return $rows;
    //     }


    //     $list = [];
    //     $indexs = array_rand($rows, $rowCount);
    //     if ($rowCount == 1) {
    //         return [$rows[$indexs]];
    //     }
    //     foreach ($indexs as $index) {
    //         $list[] = $rows[$index];
    //     }
    //     return $list;
    // }


    public static function cdnRowUrl(&$row, $fieldnames = [])
    {
        foreach ($fieldnames as $fieldname) {
            $row[$fieldname] = XcRequestUtils::cdnurl($row[$fieldname]);
        }
    }

    public static function cdnRowUrls(&$row, $fieldnames = [])
    {
        foreach ($fieldnames as $fieldname) {
            $row[$fieldname] = XcRequestUtils::cdnurls($row[$fieldname]);
            $row[$fieldname . "_array"] = explode(',', XcRequestUtils::cdnurls($row[$fieldname]));
        }
    }
    public static function cdnListUrl(&$list, $fieldnames = [])
    {
        foreach ($list as $key => $item) {
            foreach ($fieldnames as $fieldname) {
                $list[$key][$fieldname] = XcRequestUtils::cdnurl($list[$key][$fieldname]);
            }
        }
    }

    public static function cdnListUrls(&$list, $fieldnames = [])
    {
        foreach ($list as $key => $item) {
            foreach ($fieldnames as $fieldname) {
                $list[$key][$fieldname] = XcRequestUtils::cdnurls($list[$key][$fieldname]);
                $list[$key][$fieldname . "_array"] = explode(',', XcRequestUtils::cdnurls($list[$key][$fieldname]));
            }
        }
    }

  

    public static function save($dao, $id, $data)
    {
        $row = static::getRowById($dao, $id);
        $row->save($data);
        return $row;
    }

    public static function create($dao, $data)
    {
        $dao->insert($data);
        $id = $dao->getLastInsID();
        $row = static::getRowById($dao, $id);

        if (isset($data['weigh']) && $data['weigh'] == 0) {
            $row->save(['weigh' => $row->id]);
        }
        return $row;
    }

    public static function delete($dao, $id)
    {
        static::save($dao, $id, ['status' => "hidden"]);
    }

    public static function deleteRows($dao, $wheres)
    {
        $list = static::getRowBySql($dao, $wheres);
        foreach ($list as $item) {
            static::delete($dao, $item['id']);
        }
    }

    /**
     * 
        $datas = [["id" => 1, "name" => "D1-", "csmitsm_dmocategory_id" => 1], ["id" => null, "name" => "DN", "csmitsm_dmocategory_id" => 1]];
        XcDaoUtils::createOrUpdateOrDeleteDatas(new \app\admin\model\csmitsm\Dmo(), $datas, ["id"], "id", ["name", "csmitsm_dmocategory_id"], [['csmitsm_dmocategory_id', '=', 1]], true, true);
     * @return array
     */
    public static function createOrUpdateOrDeleteDatas($dao, $datas, $pkFields, $writeinDataidFieldname = null, $dataFields = null, $whereFieldValues = [], $hasNormalField = true, $isLogicDelete = true)
    {
        $list = static::getListBySql($dao, $whereFieldValues, null, null, $hasNormalField);
        // create or update
        foreach ($datas as $data) {
            $isFound = false;
            foreach ($list as $row) {
                $isEqual = true;
                foreach ($pkFields as $pkField) {
                    if ($data[$pkField] != $row[$pkField]) {
                        $isEqual = false;
                    }
                }
                if ($isEqual === true) {
                    $isFound = true;
                    break;
                }
            }

            $toSaveModel = [];
            if ($dataFields == null) {
                $toSaveModel = $data;
            } else {
                foreach ($dataFields as $dataField) {
                    $toSaveModel[$dataField] = $data[$dataField];
                }
            }

            if ($isFound === false) {
                $row = static::create($dao, $toSaveModel);
            } else {
                $row->save($toSaveModel);
            }
            if ($writeinDataidFieldname != null) {
                $data[$writeinDataidFieldname] = $row['id'];
            }
        }

        // delete
        foreach ($list as $row) {
            $isFound = false;
            foreach ($datas as $data) {
                $isEqual = true;
                foreach ($pkFields as $pkField) {
                    if ($data[$pkField] != $row[$pkField]) {
                        $isEqual = false;
                    }
                }
                if ($isEqual === true) {
                    $isFound = true;
                    break;
                }
            }
            if ($isFound === false) {
                if ($isLogicDelete === true) {
                    $row->save(['status' => 'hidden']);
                } else {
                    $row->delete();
                }
            }
        }

        return $datas;
    }
}
